﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Ionic.Zip;


namespace ShadowEraDeckEditor
{
    public partial class FormDeckBuilder : Form
    {
        #region variable and form inits

        private Deckdb[] card = new Deckdb[2000];
        Hero deckHero;
        Settings Settings = new Settings();
        List<string> _lbox1 = new List<string>();
        List<string> _lbox2 = new List<string>();
        int[] deckArray;
        int buttonClicked = 1;
        int[] list2SortArray;
        //public string tempdeck { get; set; }
 

        //Form Constructor
        public FormDeckBuilder()
        {
            InitializeComponent();
            if(File.Exists("update.exe"))
                File.Delete("update.exe");
            if (Settings.datVersion == "exit")
            {
                MessageBox.Show("You are missing \"carddb.dat\", launching updater.");
                var updateForm = new FormUpdate();
                updateForm.ShowDialog();
            } 
            InitializeDeck();
        }

        //Form Loading Point, inits etc
        private void Form1_Load(object sender, EventArgs e)
        {
            this.Location = Owner.Location;
            /*//initialize pic box on form load with blank SE card, set to keep aspect ratio, and sets location
            string picPath = Path.GetDirectoryName(Application.ExecutablePath);
            picPath = System.IO.Path.Combine(picPath, "images");
            picPath += "\\unknown.jpg";
            pictureBox1.ImageLocation = picPath;
            MemoryStream defaultPic = new MemoryStream();
            using (ZipFile zip = ZipFile.Read("carddb.dat"))
            {
                zip.Password = "c@n7cr4kD1zSh!t";
                ZipEntry z = zip["images\\unknown.jpg"];
                z.Extract(defaultPic);
                if (defaultPic != null)
                {
                    pictureBox1.Image = Image.FromStream(defaultPic);
                }
            }*/
            pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
            //disable buttons
            buttonAllies.Enabled = false;
            buttonCAbilities.Enabled = false;
            buttonRAbilities.Enabled = false;
            buttonEquips.Enabled = false;
            ToolBarChecks();

            list1_update(buttonClicked);
        }

        //initialize the cards
        private void InitializeDeck()
        {
            //read in entire file to "dblines"
            //const string f = "carddb.ini";
            List<string> dblines = new List<string>();
            ZipFile zip = ZipFile.Read("carddb.dat");
            zip.Password = "c@n7cr4kD1zSh!t";
            ZipEntry z = zip["carddb.ini"];
            MemoryStream carddatabase = new MemoryStream();
            z.Extract(carddatabase);
            carddatabase.Position = 0;
            using (StreamReader r = new StreamReader(carddatabase))
            {
                string line;
                while ((line = r.ReadLine()) != null)
                {
                    dblines.Add(line);
                }
            }
            //run through entire file, lines where not {} create new card
            int dbcount = 0;
            foreach (string s in dblines)
            {
                bool test = s.StartsWith("[");
                if (!test)
                {
                    this.card[dbcount] = new Deckdb(s);
                    dbcount += 1;
                }
            }
            //write last card in arrary's ID to be equal to number of total cards in DB
            dbcount -= 1;
            string totalcount = dbcount.ToString() + ",a,a,a,a,a";
            card[1999] = new Deckdb(totalcount);
            zip.Dispose();
        }
        #endregion

        #region listbox functions (main parts of program)

        //List 1 update, updates list1 items based on which button is active
        private void list1_update(int button)
        {
            _lbox1.Clear();
            switch (button)
            {
                //check for Hero cards and add them to box
                case 1:
                    for (int x = 0; x <= card[1999].cardID; x++)
                        if (card[x].cardType == "Hero")
                            _lbox1.Add(card[x].cardName);
                    break;
                //check for Allies that match the Hero Class and add to box
                case 2:
                    for (int x = 0; x <= card[1999].cardID; x++)
                        if ((card[x].cardRace == deckHero.heroRace && card[x].cardType == "Ally") && deckArray[card[x].cardID] < 4)
                            _lbox1.Add(card[x].cardName);
                    break;
                //check for class abilities, add to box
                case 3:
                    for (int x = 0; x <= card[1999].cardID; x++)
                        if ((card[x].cardType == "cAbility" && card[x].cardClass == deckHero.heroClass) && deckArray[card[x].cardID] < 4)
                            _lbox1.Add(card[x].cardName);
                    break;
                //check for race abilities, add to box
                case 4:
                    for (int x = 0; x <= card[1999].cardID; x++)
                        if (((card[x].cardType == "rAbility" && card[x].cardRace == deckHero.heroRace) || card[x].cardRace == "Neutral") && deckArray[card[x].cardID] < 4)
                            _lbox1.Add(card[x].cardName);
                    break;
                //check for weapons and armors, add to box
                case 5:
                    for (int x = 0; x <= card[1999].cardID; x++)
                        if ((card[x].cardType == "Equip" && (card[x].cardClass == deckHero.heroClass || card[x].cardWepClass == deckHero.heroClass)) && deckArray[card[x].cardID] < 4)
                            _lbox1.Add(card[x].cardName);
                    break;
            }
            listBox1.DataSource = null;
            listBox1.DataSource = _lbox1;
        }

        //list 2 update, updates list2 items based on clicks
        private void list2_update()
        {
            listBox2.DataSource = null;
            _lbox2.Clear();
            list2SortArray = new int[4] { 0, 0, 0, 0 };
            for (int x = 0; x < deckArray.Length; x++)
            {
                if (deckArray[x] != 0)
                {
                    //where the array isn't empty, find its matching card ID and write it to listbox (formatted)
                    for (int y = 0; y <= card[1999].cardID; y++)
                    {
                        if (card[y].cardID == x)
                        {

                            if (card[y].cardType == "Ally" && list2SortArray[0] == 0)
                            {
                                _lbox2.Add("             ");
                                list2SortArray[0] = 1;
                            }
                            if (card[y].cardType == "cAbility" && list2SortArray[1] == 0)
                            {
                                _lbox2.Add("             ");
                                list2SortArray[1] = 1;
                            }
                            if (card[y].cardType == "rAbility" && list2SortArray[1] == 0)
                            {
                                _lbox2.Add("             ");
                                list2SortArray[1] = 1;
                            }
                            if (card[y].cardType == "Equip" && list2SortArray[3] == 0)
                            {
                                _lbox2.Add("             ");
                                list2SortArray[3] = 1;
                            }
                            _lbox2.Add(deckArray[x].ToString() + "     " + card[y].cardName);

                        }
                    }
                }
            }
            listBox2.DataSource = _lbox2;
            //increase deck counter
            labelDeckCount.Text = Convert.ToString(deckArray.Sum());
            list1_update(buttonClicked);
            //if the deck contains more than 30 cards, create the deck code and enable copy button
            if (deckArray.Sum() >= 30)
            {
                textBoxDeckCode.Text = DeckCode.INTtoC(deckArray);
                ((FormMenu)Owner).currentdeck = textBoxDeckCode.Text;
                buttonCopy.Enabled = true;
                buttonCopyDeck.Enabled = true;
            }
        }

        //listbox 1 single click, update image
        private void listBox1_MouseClick(object sender, EventArgs e)
        {
            if (listBox1.SelectedItem != null)
            {
                //if listbox is single clicked, update the image for it
                for (int x = 0; x <= card[1999].cardID; x++)
                {
                    if (listBox1.SelectedItem == card[x].cardName)
                    {
                        pictureBox1.Image = Image.FromStream(card[x].cardURL);
                    }
                }
            }
        }

        //listbox 1 double click
        private void listBox1_DoubleClick(object sender, EventArgs e)
        {
            if (listBox1.SelectedItem != null)
            {
                for (int x = 0; x <= card[1999].cardID; x++)
                {
                    //find the card they clicked
                    if (listBox1.SelectedItem == card[x].cardName)
                    {
                        //if that card is a Hero, destroy/create the Hero class and create the deck array
                        if (card[x].cardType == "Hero")
                        {
                            deckHero = new Hero(card[x].cardID, card[x].cardRace, card[x].cardClass);
                            //deckArray = new int[card[card[1999].cardID].cardID + 1];//(HERE)
                            deckArray = new int[GetHighest()];
                            buttonAllies.Enabled = true;
                            buttonCAbilities.Enabled = true;
                            buttonRAbilities.Enabled = true;
                            buttonEquips.Enabled = true;
                        }
                        //then add the card to the deck array
                        if(deckArray[card[x].cardID] < 4) {
                            deckArray[card[x].cardID] += 1;
                        }
                    }
                 }
                //update the listboxes
                list1_update(buttonClicked);
                list2_update();
            }
        }

        //listbox 2 single click, update image
        private void listBox2_MouseClick(object sender, EventArgs e)
        {
            if (listBox2.SelectedItem != null)
            {
                //if listbox2 is single clicked, update the image for it 
                for (int x = 0; x <= card[1999].cardID; x++)
                {
                    string buffer = listBox2.SelectedItem.ToString();
                    buffer = buffer.Substring(6);
                    if (buffer == card[x].cardName)
                    {
                        pictureBox1.Image = Image.FromStream(card[x].cardURL);
                    }
                }
            }
        }

        //listbox 2 double click
        private void listBox2_DoubleClick(object sender, EventArgs e)
        {
            if (listBox2.SelectedItem != null)
            {
                string buffer = listBox2.SelectedItem.ToString();
                buffer = buffer.Substring(6);
                for (int x = 0; x <= card[1999].cardID; x++)
                {
                    if (buffer == card[x].cardName)
                    {
                        //if its a hero, destroy the world
                        if (card[x].cardType == "Hero")
                            destroyTheWorld();
                        //then remove the card to the deck array
                        if (deckArray[card[x].cardID] > 0)
                        {
                            deckArray[card[x].cardID] -= 1;
                        }
                    }
                }
            }
            list1_update(buttonClicked);
            list2_update();
        }
        #endregion

        #region imports / exports
        //open dialog
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openFileDialog.FileName = "";
            openFileDialog.Filter = "Deck files|*.dek";
            openFileDialog.InitialDirectory = Settings.lastFolder;
            openFileDialog.ShowDialog(this);
            if (openFileDialog.FileName != "")
            {
                if (openFileDialog.FileName.Substring(openFileDialog.FileName.Length - 4) == ".dek")
                {
                    string line;
                    using (StreamReader reader = new StreamReader(openFileDialog.FileName))
                    {
                        line = reader.ReadLine();
                    }
                    Settings.WriteFolder(openFileDialog.FileName);
                    DeckImport(line);
                }
                else
                    MessageBox.Show("You can only open .dek files!");
            }
        }

        //save dialog
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if( deckArray != null)
            if (deckArray.Sum() > 29)
            {
                saveFileDialog.InitialDirectory = Settings.lastFolder;
                saveFileDialog.Filter = "Deck file|*.dek|TXT file|*.txt";
                saveFileDialog.ShowDialog(this);
                if (saveFileDialog.FileName != "")
                {
                    //string extension = saveFileDialog.FileName.Substring(saveFileDialog.FileName.Length - 4);
                    //If .dek file:
                    if (saveFileDialog.FileName.Substring(saveFileDialog.FileName.Length - 4) == ".dek")
                        using (StreamWriter writer = new StreamWriter(saveFileDialog.FileName))
                        {
                            writer.Write(DeckCode.INTtoC(deckArray));
                        }
                    //If .txt file:
                    if (saveFileDialog.FileName.Substring(saveFileDialog.FileName.Length - 4) == ".txt")
                        using (StreamWriter writer = new StreamWriter(saveFileDialog.FileName))
                        {
                            writer.Write(CopyDecklist());
                        }
                    Settings.WriteFolder(saveFileDialog.FileName);
                }
                else
                    MessageBox.Show("You need at least 30 cards to save a deck.");
            }
            else
                MessageBox.Show("A deck requires at least 30 cards to be saved.");
            if(deckArray == null)
                MessageBox.Show("A deck requires at least 30 cards to be saved.");
        }

        //deck import
        public void DeckImport(string s)
        {
            if (s == "teamass")
            {
                ((FormMenu)Owner).userlevel = 2;
                ToolBarChecks();
            }
            else if (s == "godmode")
            {
                ((FormMenu)Owner).userlevel = 3;
                ToolBarChecks();
            }
            else
            {
                if (DeckCode.Verify(s))
                {
                    destroyTheWorld();
                    //deckArray = DeckCode.CtoINT(s, deckArray.Length);
                    /*deckArray = DeckCode.CtoINT(s, GetHighest());
                    for (int x = 0; x < card[1999].cardID; x++)
                        if (deckArray[x] == 1)
                            if (card[x].cardType == "Hero")
                                deckHero = new Hero(card[x].cardID, card[x].cardRace, card[x].cardClass);*/
                    deckArray = DeckCode.CtoINT(s, GetHighest());
                    for (int x = 0; x < card[1999].cardID; x++)
                        if (deckArray[x] == 1)
                            for (int y = 0; y < card[1999].cardID; y++)
                                if (card[y].cardID == x)
                                {
                                    deckHero = new Hero(card[y].cardID, card[y].cardRace, card[y].cardClass);
                                    x = card[1999].cardID + 1;
                                    y = card[1999].cardID + 1;
                                }

                    buttonClicked = 1;
                    buttonAllies.Enabled = true;
                    buttonCAbilities.Enabled = true;
                    buttonRAbilities.Enabled = true;
                    buttonEquips.Enabled = true;
                    list1_update(buttonClicked);
                    list2_update();
                    //code here shows the imported Hero pic
                    for (int x = 0; x <= card[1999].cardID; x++)
                    {
                        listBox2.SelectedIndex = 0;
                        string buffer = listBox2.SelectedItem.ToString();
                        buffer = buffer.Substring(6);
                        if (buffer == card[x].cardName)
                        {
                            pictureBox1.Image = Image.FromStream(card[x].cardURL);
                        }
                    }
                }
                else
                    MessageBox.Show("This is not a valid deck");
            }
        }

        //decklist to buffer string
        public string CopyDecklist()
        {
            StringBuilder buffer = new StringBuilder();

            for (int i = 0; i < listBox2.Items.Count; i++)
            {
                if (listBox2.Items[i].ToString() != "             ")
                    buffer.Append(listBox2.Items[i].ToString());
                //buffer.Append("\n");
                buffer.Append(Environment.NewLine);
            }
            buffer.Remove(buffer.Length - 2, 2);
            return buffer.ToString();
        }
        #endregion

        //destroy the world, reset the form back to its starting point
        private void destroyTheWorld()
        {
            _lbox1.Clear();
            _lbox2.Clear();
            listBox1.DataSource = null;
            listBox2.DataSource = null;
            buttonAllies.Enabled = false;
            buttonCAbilities.Enabled = false;
            buttonRAbilities.Enabled = false;
            buttonEquips.Enabled = false;
            buttonCopy.Enabled = false;
            buttonCopyDeck.Enabled = false;
            deckHero = null;
            textBoxDeckCode.Text = null;
            labelDeckCount.Text = "0";
            //deckArray = new int[card[card[1999].cardID].cardID + 1]; //(HERE)
            deckArray = new int[GetHighest()];
            ((FormMenu)Owner).currentdeck = "";
            
            buttonAllies.Top = buttonHeroes.Top + 234;
            buttonCAbilities.Top = buttonAllies.Top + 45;
            buttonRAbilities.Top = buttonCAbilities.Top + 45;
            buttonEquips.Top = buttonRAbilities.Top + 45;
            listBox1.Top = buttonHeroes.Top + 30;
            buttonClicked = 1;
            list1_update(buttonClicked);
        }

        //get the highest card ID
        public int GetHighest()
        {
            int z = 0;
            for (int x = 0; x <= card[1999].cardID; x++)
            {
                if (card[x].cardID > z)
                    z = card[x].cardID;
            }
            z += 1;
            return z;
        }

        private void exit()
        {
            //Owner.Location = this.Location;
            //((FormMenu)Owner).nextform = 1;
            this.Close();
        }


        #region button clicks (cards)
        //Below are the card button click functions, which just move screen buttons and call list update1
        private void buttonHeroes_Click(object sender, EventArgs e)
        {
            buttonClicked = 1;
            list1_update(buttonClicked);
            //code to move buttons and listbox properly when clicked
            buttonAllies.Top = buttonHeroes.Top + 234;
            buttonCAbilities.Top = buttonAllies.Top + 45;
            buttonRAbilities.Top = buttonCAbilities.Top + 45;
            buttonEquips.Top = buttonRAbilities.Top + 45;
            listBox1.Top = buttonHeroes.Top + 30;
        }

        private void buttonAllies_Click(object sender, EventArgs e)
        {
            buttonClicked = 2;
            list1_update(buttonClicked);
            buttonAllies.Top = buttonHeroes.Top + 45;
            buttonCAbilities.Top = buttonAllies.Top + 234;
            buttonRAbilities.Top = buttonCAbilities.Top + 45;
            buttonEquips.Top = buttonRAbilities.Top + 45;
            listBox1.Top = buttonAllies.Top + 30;
        }

        private void buttonCAbilities_Click(object sender, EventArgs e)
        {
            buttonClicked = 3;
            list1_update(buttonClicked);
            buttonAllies.Top = buttonHeroes.Top + 45;
            buttonCAbilities.Top = buttonAllies.Top + 45;
            buttonRAbilities.Top = buttonCAbilities.Top + 234;
            buttonEquips.Top = buttonRAbilities.Top + 45;
            listBox1.Top = buttonCAbilities.Top + 30;
        }

        private void buttonRAbilities_Click(object sender, EventArgs e)
        {
            buttonClicked = 4;
            list1_update(buttonClicked);
            buttonAllies.Top = buttonHeroes.Top + 45;
            buttonCAbilities.Top = buttonAllies.Top + 45;
            buttonRAbilities.Top = buttonCAbilities.Top + 45;
            buttonEquips.Top = buttonRAbilities.Top + 234;
            listBox1.Top = buttonRAbilities.Top + 30;
        }

        private void buttonEquips_Click(object sender, EventArgs e)
        {
            buttonClicked = 5;
            list1_update(buttonClicked);
            buttonAllies.Top = buttonHeroes.Top + 45;
            buttonCAbilities.Top = buttonAllies.Top + 45;
            buttonRAbilities.Top = buttonCAbilities.Top + 45;
            buttonEquips.Top = buttonRAbilities.Top + 45;
            listBox1.Top = buttonEquips.Top + 30;
        }
        #endregion

        #region other buttons (import, clear, copy, switch tabs)

        //clear deck
        private void buttonClearDeck_Click(object sender, EventArgs e)
        {
            destroyTheWorld();
        }

        //copy deck code button
        private void buttonCopy_Click(object sender, EventArgs e)
        {
            string text = textBoxDeckCode.Text;
            Clipboard.Clear();
            Clipboard.SetText(text);
        }

        //copy deck as TXT
        private void buttonCopyDeck_Click(object sender, EventArgs e)
        {
            Clipboard.Clear();
            Clipboard.SetText(CopyDecklist());
        }

        //import deck code
        private void buttonImport_Click(object sender, EventArgs e)
        {
            string input = Microsoft.VisualBasic.Interaction.InputBox("Paste deck code", "Paste deck code", "", 300, 300);

            if (input != "")
            {
                DeckImport(input);
            }
        }
        #endregion

        #region menubar
        //switch to deckhack
        private void hacksMenuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Owner.Location = this.Location;
            ((FormMenu)Owner).nextform = 4;
            this.Close();
        }

        //switch to deckhacklite
        private void deckHackLiteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Owner.Location = this.Location;
            ((FormMenu)Owner).nextform = 3;
            this.Close();
        }

        //security tool converter pop up
        private void securityMenuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormSecurity _security = new FormSecurity();
            _security.ShowDialog();
        }

        //"they clicked go to AI builder"
        private void aIBuilderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Owner.Location = this.Location;
            ((FormMenu)Owner).nextform = 2;
            this.Close();
        }

        //exit the program (from File->Exit)
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ((FormMenu)Owner).nextform = 5;
            this.Close();
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormOptions _options = new FormOptions();
            _options.ShowDialog();
        }

        private void developerMenuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Owner.Location = this.Location;
            ((FormMenu)Owner).nextform = 2;
            this.Close();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var about = new FormAbout();
            about.ShowDialog();
        }

        private void updateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var update = new FormUpdate();
            update.ShowDialog();
        }
        #endregion

        private void ToolBarChecks()
        {
            if (((FormMenu)Owner).userlevel == 1)
            {
                securityMenuToolStripMenuItem.Visible = false;
                deckHackLiteToolStripMenuItem.Visible = false;
                hacksMenuToolStripMenuItem.Visible = false;
                developerMenuToolStripMenuItem.Visible = false;
            }
            if (((FormMenu)Owner).userlevel == 2)
            {
                securityMenuToolStripMenuItem.Visible = true;
                deckHackLiteToolStripMenuItem.Visible = false;
                hacksMenuToolStripMenuItem.Visible = false;
                developerMenuToolStripMenuItem.Visible = false;
            }
            if (((FormMenu)Owner).userlevel == 3)
            {
                securityMenuToolStripMenuItem.Visible = true;
                deckHackLiteToolStripMenuItem.Visible = true;
                hacksMenuToolStripMenuItem.Visible = true;
                developerMenuToolStripMenuItem.Visible = true;
            }
        }


    }
}
